#pragma once
#include<cstring>
#include<iostream>
#include<string>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<unistd.h>
using namespace std;

#define MSG_TYPE_CLIENT 1
#define MSG_TYPE_SERVER 2


//ftok生成key需要的路径和proj_Id
#define PATHNAME "/home/zhuang/msgQueue"
#define PROJID 0x123
const int defaultfd = -1;

#define CREATE_MSQ  (IPC_CREAT | IPC_EXCL | 0666)
#define GET_MSQ (IPC_CREAT)
 
class MsgQueue
{
public:
   MsgQueue()
   :_msgid(defaultfd)
   {
   }

   ~MsgQueue()
   {
      // Destroy();
   }

   struct msgbuf 
   {
       long mtype;
       char mtext[1024];
   };

   void Create(int flag)
   {
     //1.获取key值
     key_t key = ::ftok(PATHNAME,PROJID);
     if(key == -1)
     {
        cerr << "ftok error" << endl;
        return;
     }
     //2.创建消息队列
     _msgid = ::msgget(key,flag);
     if(_msgid == -1)
     {
        cerr << "create MsgQueue error " << endl;
        return;
     }
     //创建成功
     cout << "MsgQueue create success : " << _msgid << " key : " << std::hex << key << endl;
   }

   void Destroy()
   {
      int n = ::msgctl(_msgid,IPC_RMID,0);
      if(n == -1) 
      {
        cerr << "destroy MsgQueue error" << endl;
        return;
      }
      cout << "destroy MsgQueue Success" << endl;
   }
    
   void GetAttr() //获取属性
   {
      struct msqid_ds msg;
      int n = ::msgctl(_msgid,IPC_STAT,&msg);
      if(n == -1)
      {
         cerr << "GetAttr Error" << endl;
         return;
      }
      //打印信息
      cout << "msq_qnum: " << msg.msg_qnum << endl;
      cout << "_key: " << msg.msg_perm.__key << endl;
   }


   void Send(int type,string& text) //自己消息体类型，要发的消息
   {
       //1.创建自定义消息体并且初始化清空里面的内容
       struct msgbuf  mbuff;
       //1.1最好清空
       memset(&mbuff,0,sizeof(mbuff));
       //1.2初始化
       mbuff.mtype = type;
       memcpy(mbuff.mtext,text.c_str(),text.size());
       //2.send发送
       int n = ::msgsnd(_msgid,&mbuff,sizeof(mbuff.mtext),0);
       if(n == -1)
       {
         cerr << "msgsnd error "  << endl;
         return;
       }
       cout << "send message: "<< text << endl;
   }

   void Recv(int type,string& text) //要收的消息类型.输出型参数表示接收到的消息
   {
      //1.自定义结构体来接收消息
      struct msgbuf  mbuff;
      memset(&mbuff,0,sizeof(mbuff));
      //2.接收消息
      int n = ::msgrcv(_msgid,&mbuff,sizeof(mbuff.mtext),type,0);
      if(n == -1)
      {
         cerr << "recv error " << n << endl;
         return;
      }
      //接收成功表示接收到的字符个数
      mbuff.mtext[n] = '\0';
      text = mbuff.mtext;
      type = mbuff.mtype;
   }

private:   
   int _msgid;  
};


class Server : public MsgQueue 
{
  public:
     Server()
     {
         MsgQueue::Create(CREATE_MSQ);
     }
     ~Server()
     {
        Destroy();
     }

};


class Client : public MsgQueue 
{
  public:
     Client()
     {
        MsgQueue::Create(GET_MSQ);
     }
     ~Client()
     {}
};
